package com.wmh.baseservice.merchant.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.wmh.baseservice.admin.pojo.AdProfit;
import com.wmh.baseservice.admin.service.AdProfitService;
import com.wmh.baseservice.common.config.KeyConfig;
import com.wmh.baseservice.common.ex.ServiceException;
import com.wmh.baseservice.common.redis.config.RedisConfig;
import com.wmh.baseservice.common.redis.utils.RedisUtil;
import com.wmh.baseservice.common.shiro.config.ShiroConfig;
import com.wmh.baseservice.common.utils.CommUtil;
import com.wmh.baseservice.common.utils.LogUtil;
import com.wmh.baseservice.common.utils.ShiroMd5Util;
import com.wmh.baseservice.common.utils.UUIDUtil;
import com.wmh.baseservice.common.utils.returnbody.ReturnBody;
import com.wmh.baseservice.merchant.pojo.*;
import com.wmh.baseservice.merchant.mapper.MerchantPlotRegionMapper;
import com.wmh.baseservice.merchant.service.*;
import com.wmh.baseservice.common.mybatisplus.methods.CommonServiceImpl;
import com.wmh.baseservice.system.pojo.SysMessage;
import com.wmh.baseservice.system.pojo.SysParams;
import com.wmh.baseservice.system.service.SysMessageService;
import com.wmh.baseservice.system.service.SysParamsService;
import com.wmh.baseservice.user.pojo.UsIncomeExpend;
import com.wmh.baseservice.user.pojo.UsInfo;
import com.wmh.baseservice.user.pojo.UsRentOrder;
import com.wmh.baseservice.user.service.UsIncomeExpendService;
import com.wmh.baseservice.user.service.UsInfoService;
import com.wmh.baseservice.user.service.UsRentOrderService;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * @author wmh generator
 * @since 2022-01-04
 */
@Service
public class MerchantPlotRegionServiceImpl extends CommonServiceImpl<MerchantPlotRegionMapper, MerchantPlotRegion> implements MerchantPlotRegionService {

    @Resource
    private MerchantPlotRegionMapper merchantPlotRegionMapper;
    @Resource
    private MerchantRolePermissionsService merchantRolePermissionsService;
    @Resource
    private MerchantInfoService merchantInfoService;
    @Resource
    private UsInfoService usInfoService;
    @Resource
    private RedisUtil redisUtil;
    @Resource
    private MerchantPlotRentalMenuService merchantPlotRentalMenuService;
    @Resource
    private MerchantPlotRentService merchantPlotRentService;
    @Resource
    private MerchantPlotRegionService merchantPlotRegionService;
    @Resource
    private UsRentOrderService usRentOrderService;
    @Resource
    private SysMessageService sysMessageService;
    @Resource
    private MerchantRoleMenuService merchantRoleMenuService;
    @Resource
    private SysParamsService sysParamsService;
    @Resource
    private AdProfitService adProfitService;
    @Resource
    private MerchantIncomeExpendService merchantIncomeExpendService;
    @Resource
    private UsIncomeExpendService usIncomeExpendService;

    //租赁商家默认菜单
    public final Long[] menuIds = {98L, 100L, 101L, 102L, 104L, 103L};

    @Override
    public IPage<MerchantPlotRegion> getList(Page<Object> vegetablePage, Map<String, Object> map) {
        return merchantPlotRegionMapper.getList(vegetablePage, map);
    }

    @Override
    public IPage<MerchantPlotRegion> usList(Page<MerchantPlotRegion> merchantPlotRegionPage, Map<String, Object> map) {
        return merchantPlotRegionMapper.usList(merchantPlotRegionPage, map);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void payAmount(UsRentOrder usRentOrder, MerchantPlotRegion merchantPlotRegion, UsInfo usInfo) {
        //更改区域状态
        merchantPlotRegion.setStatus(2);
        //原商家余额添加
        MerchantInfo rawMerchantInfo = merchantPlotRegionService.getRawMerchantInfo(merchantPlotRegion.getId());
        if (!CommUtil.checkNull(rawMerchantInfo)) {
            //该区域没有被租出去过，那么当前区域商家就是原商家
            rawMerchantInfo = merchantInfoService.getByIdForUpdate(merchantPlotRegion.getMerchantId());
        }
        SysParams sysParams = sysParamsService.getByIdForUpdate(19L);
        BigDecimal amount = usRentOrder.getPayAmount();
        BigDecimal cost = amount.multiply(new BigDecimal(sysParams.getValue()));
        amount = amount.subtract(cost);
        rawMerchantInfo.setBalance(rawMerchantInfo.getBalance().add(amount));
        //平台收入流水，商家收入流水，用户支出流水
        AdProfit adProfit = new AdProfit().setOrigin("用户租赁区域抽成").setMoney(cost).setStatus(1);
        MerchantIncomeExpend merchantIncomeExpend = new MerchantIncomeExpend().setStatus(1).setRemark("租赁区域收入")
                .setMoney(amount).setOrderNum(usRentOrder.getOrderNum()).setMerchantId(rawMerchantInfo.getId());
        UsIncomeExpend usIncomeExpend = new UsIncomeExpend().setType(1).setStatus(-1)
                .setMoney(amount).setRemark("租赁区域支出").setUsId(usRentOrder.getUsId());
        //发送消息
        SysMessage merchantMessage = new SysMessage().setMerchantId(merchantIncomeExpend.getMerchantId())
                .setTitle(String.format("您的%s区域已租出", merchantPlotRegion.getName()))
                .setContent(String.format("有用户租了您的%s区域，选够的套餐id是%s，您可进入商家后台-已租出的区域中查看明细，" +
                                "从现在开始该区域所有收益均归承租方所有，到期后如该用户没有续租，则会自动转回您的土地中。"
                        , merchantPlotRegion.getName(), usRentOrder.getRentMenuId())).setStatus(0);

        SysMessage usMessage = new SysMessage().setTitle(String.format("您已成功承租%s区域", merchantPlotRegion.getName())).setUsId(usRentOrder.getUsId())
                .setContent("您可在我的-商家后台-土地管理-果蔬管理处上传果蔬了，该土地所有收益均为您所有，建议您联系原商家前往土地实地考察后再操作哦")
                .setStatus(0);

        //查询租赁套餐
        MerchantPlotRentalMenu merchantPlotRentalMenu = merchantPlotRentalMenuService.getByIdForUpdate(usRentOrder.getRentMenuId());
        //如果租该土地的用户不是商家，那么生成商家账号并发送消息，定时器每天减少租期，到期后该商家没续租则冻结该商家,然后冻结商家身份和商家操作，商家可以选择重新入驻，或者续租
        if (!CommUtil.checkNull(usInfo.getMerchantId())) {
            //1、生成商家账号
            String code = UUIDUtil.getCode();
            //生成商家账号
            String substring = code.substring(24);
            String salt = ShiroMd5Util.createSalt();
            String pwd = ShiroMd5Util.encodePwd(substring + KeyConfig.SHIRO_SALE, salt);
            MerchantInfo merchantInfo = new MerchantInfo().setStatus(0).setAccount(usInfo.getPhone()).setSalt(salt)
                    .setPassword(pwd).setName(usInfo.getName()).setPhone(usInfo.getPhone()).setUsId(usInfo.getId()).setShares(1D).setType(2);
            merchantInfo.setParentId(-1L);
            merchantInfo.setStoreAvatar("/files/vegetable_mall_file/default/storeAvatar.png");
            merchantInfo.setStoreName("默认店铺名称");

            if (!merchantInfoService.save(merchantInfo)) {
                throw new ServiceException("审核：添加商家账号出错");
            }
            SysMessage sysMessage = new SysMessage().setUsId(usInfo.getId()).setTitle("您已通过租赁土地区域成为商家，现在您可以登录商家后台对该区域进行操作了")
                    .setContent(String.format("您已成功入驻平台，请使用电脑端登录商家后台，网址为:https://www.tdtye.com/merchant，账号为您当前用户所绑定手机号，默认密码为：%s，可进入商家后台进行修改", substring));
            if (!sysMessageService.save(sysMessage)) {
                throw new ServiceException();
            }
            //添加租赁合同
            MerchantPlotRent merchantPlotRent = new MerchantPlotRent().setRentUsId(usInfo.getId()).setRawMerchantId(merchantPlotRegion.getMerchantId()).setDay(merchantPlotRentalMenu.getDay()).
                    setPayAmount(usRentOrder.getPayAmount()).setRentMenuId(merchantPlotRentalMenu.getId()).setPlotId(merchantPlotRegion.getPlotId()).
                    setRegionId(merchantPlotRegion.getId()).setRentMerchantId(merchantInfo.getId()).setStatus(1);
            if (!merchantPlotRentService.save(merchantPlotRent)) {
                throw new ServiceException();
            }
            //回写租赁订单合同号
            usRentOrder.setRentId(merchantPlotRent.getId());

            //回写区域id所属商家
            merchantPlotRegion.setMerchantId(merchantInfo.getId());
            if (!merchantPlotRegionService.updateById(merchantPlotRegion)) {
                throw new ServiceException();
            }

            //1-3设置默认角色
            MerchantRolePermissions merchantRolePermissions = new MerchantRolePermissions().setRole("merchant").setMerchantId(merchantInfo.getId()).setType(1);
            if (!merchantRolePermissionsService.save(merchantRolePermissions)) {
                throw new ServiceException("审核：添加商家角色权限出错");
            }
            //1-4回写角色id
            merchantInfo.setRoleId(merchantRolePermissions.getId());
            if (!merchantInfoService.updateById(merchantInfo)) {
                throw new ServiceException("审核：回写商家角色id出错");
            }
            //1-6回写用户商家id
            usInfo.setMerchantId(merchantInfo.getId());
            //设置默认菜单
            for (Long menuId : menuIds) {
                MerchantRoleMenu merchantRoleMenu = new MerchantRoleMenu().setMenuId(menuId).setRoleId(merchantRolePermissions.getId()).setStatus(1);
                if (!merchantRoleMenuService.save(merchantRoleMenu)) {
                    throw new ServiceException("审核： 添加子商家默认菜单错误");
                }
            }
            //1-5将角色权限添加进redis队列
            String project = RedisConfig.KEY_INFO;
            String key = "role_permissions_" + merchantInfo.getId() + ShiroConfig.SHIRO_MERCHANT + project;
            try {
                SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
                Set<String> roles = new HashSet<>();
                roles.add(merchantRolePermissions.getRole());
                info.setRoles(roles);
                MerchantRolePermissions parent = new MerchantRolePermissions().setPermissions("所有权限").setMerchantId(merchantInfo.getId()).setType(2);
                if (!merchantRolePermissionsService.save(parent)) {
                    throw new ServiceException("审核：添加商家角色权限出错");
                }
                Set<String> per = new HashSet<>();
                per.add(parent.getPermissions());
                info.setStringPermissions(per);
                redisUtil.set(key, info);
            } catch (Exception e) {
                LogUtil.error("redis角色权限添加错误,key是:" + key + "。原因是:" + e.getMessage());
            }
        } else {
            //续租或商家租地操作
            QueryWrapper<MerchantPlotRent> eq = new QueryWrapper<MerchantPlotRent>().eq(MerchantPlotRent.REGION_ID, merchantPlotRegion.getId()).eq(MerchantPlotRent.RENT_US_ID, usInfo.getId())
                    .eq(MerchantPlotRent.RENT_MERCHANT_ID, usInfo.getMerchantId());
            MerchantPlotRent merchantPlotRent = merchantPlotRentService.getOneForUpdate(eq);
            if (!CommUtil.checkNull(merchantPlotRent)) {
                //第一次租该区域
                merchantPlotRent = new MerchantPlotRent().setRentUsId(usInfo.getId()).setRawMerchantId(merchantPlotRegion.getMerchantId()).setDay(merchantPlotRentalMenu.getDay()).
                        setPayAmount(merchantPlotRentalMenu.getPrice()).setRentMenuId(merchantPlotRentalMenu.getId()).setPlotId(merchantPlotRegion.getPlotId()).
                        setRegionId(merchantPlotRegion.getId()).setRentMerchantId(usInfo.getMerchantId()).setStatus(1);
                //保存租赁合同
                if (!merchantPlotRentService.save(merchantPlotRent)) {
                    throw new ServiceException();
                }
                //回写合同id
                usRentOrder.setRentId(merchantPlotRent.getId());
                //修改区域商家id
                merchantPlotRegion.setMerchantId(usInfo.getMerchantId());
            } else {
                //续租
                MerchantInfo merchantInfo = merchantInfoService.getByIdForUpdate(usInfo.getMerchantId());
                //TODO 判断当前续租是正常续租还是重新正常租赁
                JSONObject object = JSONObject.parseObject(usRentOrder.getSnapshot());
                if (object.containsKey("deposit")) {
                    //重新正常租赁续租，修改合同押金为未退
                    merchantPlotRent.setHasDeposit(0);
                }
                merchantInfo.setStatus(0);
                //解冻
                if (!merchantInfoService.updateById(merchantInfo)) {
                    throw new ServiceException();
                }
                //添加租赁合同时间
                merchantPlotRent.setDay(merchantPlotRent.getDay() + merchantPlotRentalMenu.getDay()).setStatus(1);
                if (!merchantPlotRentService.updateById(merchantPlotRent)) {
                    throw new ServiceException();
                }
                //回写合同id
                usRentOrder.setRentId(merchantPlotRent.getId());
                //修改区域拥有人信息
                merchantPlotRegion.setMerchantId(merchantInfo.getId());
            }
            if (!merchantPlotRegionService.updateById(merchantPlotRegion)) {
                throw new ServiceException();
            }
        }
        //提交统一事务
        if (!adProfitService.save(adProfit)) {
            throw new ServiceException();
        }
        if (!merchantIncomeExpendService.save(merchantIncomeExpend)) {
            throw new ServiceException();
        }
        if (!usIncomeExpendService.save(usIncomeExpend)) {
            throw new ServiceException();
        }
        if (!usInfoService.updateById(usInfo)) {
            throw new ServiceException();
        }
        if (!usRentOrderService.updateById(usRentOrder)) {
            throw new ServiceException();
        }
        if (!sysMessageService.save(merchantMessage)) {
            throw new ServiceException();
        }
        if (!sysMessageService.save(usMessage)) {
            throw new ServiceException();
        }
        if (!merchantInfoService.updateById(rawMerchantInfo)) {
            throw new ServiceException();
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void wechatPay(String orderNum) {
        UsRentOrder rentOrder = usRentOrderService.getOneForUpdate(new QueryWrapper<UsRentOrder>().eq(UsRentOrder.ORDER_NUM, orderNum));
        MerchantPlotRegion merchantPlotRegion = merchantPlotRegionService.getByIdForUpdate(rentOrder.getRegionId());
        rentOrder.setStatus(1);
        UsInfo usInfo = usInfoService.getByIdForUpdate(rentOrder.getUsId());
        payAmount(rentOrder, merchantPlotRegion, usInfo);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public MerchantInfo getRawMerchantInfo(Long id) {
        return merchantPlotRegionMapper.getRawMerchantInfo(id);
    }
}
